import gosu.Color;

import org.jruby.*;
import org.jruby.runtime.*;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.anno.JRubyMethod;
import static org.jruby.RubyNumeric.*;
import static org.jruby.RubyFloat.*;

public class ColorProxy extends RubyObject {
  private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
    public IRubyObject allocate(Ruby runtime, RubyClass klass) {
      return new ColorProxy(runtime, klass);
    }
  };

  private Color _color;

  private final Ruby _runtime;

  public static void createColorClass(Ruby runtime) {
    RubyModule mGosu = runtime.getModule("Gosu");
    RubyClass cColor = mGosu.defineClassUnder("Color", runtime.getObject(), ALLOCATOR);

    cColor.defineAnnotatedMethods(ColorProxy.class);
  }


  public ColorProxy(Ruby runtime, RubyClass type) {
    super(runtime, type);
    _runtime = runtime;
  }


  public void setColor(Color color) { _color = color; }


  public Color getColor() { return _color; }


  @JRubyMethod(name = "initialize",
               required = 1,
               optional = 3,
               frame = true,
               visibility = Visibility.PRIVATE)
  public IRubyObject initialize(IRubyObject[] args) {
    int numArgs = Arity.checkArgumentCount(_runtime, args, 1, 4);
    if (numArgs == 1) _color = new Color((int) fix2long(args[0]));
    else if (numArgs == 2) Arity.raiseArgumentError(_runtime, numArgs, 3, 4);
    else if (numArgs == 3) _color = new Color(fix2int(args[0]), fix2int(args[1]), fix2int(args[2]));
    else _color = new Color(fix2int(args[0]), fix2int(args[1]), fix2int(args[2]), fix2int(args[3]));

    return this;
  }

  
  @JRubyMethod(name = "alpha")
  public IRubyObject alpha() {
    return _runtime.newFixnum(_color.alpha());
  }

  
  @JRubyMethod(name = "alpha=",
               required = 1)
  public IRubyObject setAlpha(IRubyObject r_alpha) {
    _color.setAlpha(fix2int(r_alpha));
    return _runtime.getNil();
  }


  @JRubyMethod(name = "red")
  public IRubyObject red() {
    return _runtime.newFixnum(_color.red());
  }

  
  @JRubyMethod(name = "red=",
               required = 1)
  public IRubyObject setRed(IRubyObject r_red) {
    _color.setRed(fix2int(r_red));
    return _runtime.getNil();
  }


  @JRubyMethod(name = "green")
  public IRubyObject green() {
    return _runtime.newFixnum(_color.green());
  }

  
  @JRubyMethod(name = "green=",
               required = 1)
  public IRubyObject setGreen(IRubyObject r_green) {
    _color.setGreen(fix2int(r_green));
    return _runtime.getNil();
  }


  @JRubyMethod(name = "blue")
  public IRubyObject blue() {
    return _runtime.newFixnum(_color.blue());
  }

  
  @JRubyMethod(name = "blue=",
               required = 1)
  public IRubyObject setBlue(IRubyObject r_blue) {
    _color.setBlue(fix2int(r_blue));
    return _runtime.getNil();
  }


  @JRubyMethod(name = "hue")
  public IRubyObject hue() {
    return newFloat(_runtime, _color.hue());
  }

  
  @JRubyMethod(name = "hue=",
               required = 1)
  public IRubyObject setHue(IRubyObject r_hue) {
    _color.setHue((float) num2dbl(r_hue));
    return _runtime.getNil();
  }


  @JRubyMethod(name = "saturation")
  public IRubyObject saturation() {
    return newFloat(_runtime, _color.saturation());
  }

  
  @JRubyMethod(name = "saturation=",
               required = 1)
  public IRubyObject setSaturation(IRubyObject r_saturation) {
    _color.setSaturation((float) num2dbl(r_saturation));
    return _runtime.getNil();
  }


  @JRubyMethod(name = "value")
  public IRubyObject value() {
    return newFloat(_runtime, _color.value());
  }

  
  @JRubyMethod(name = "value=",
               required = 1)
  public IRubyObject setValue(IRubyObject r_value) {
    _color.setValue((float) num2dbl(r_value));
    return _runtime.getNil();
  }


  @JRubyMethod(name = "from_hsv",
               required = 3,
               meta = true)
  public static IRubyObject fromHSV(IRubyObject klass, IRubyObject r_h, IRubyObject r_s, IRubyObject r_v) {
    float h = (float) num2dbl(r_h);
    float s = (float) num2dbl(r_s);
    float v = (float) num2dbl(r_v);

    Color color = Color.fromHSV(h, s, v);
    ColorProxy proxy = (ColorProxy) ((RubyClass) klass).allocate();
    proxy.setColor(color);
    return proxy;
  }


  @JRubyMethod(name = "from_ahsv",
               required = 4,
               meta = true)
  public static IRubyObject fromAHSV(IRubyObject klass, IRubyObject[] args) {
    float h = (float) num2dbl(args[1]);
    float s = (float) num2dbl(args[2]);
    float v = (float) num2dbl(args[3]);

    Color color = Color.fromAHSV(fix2int(args[0]), h, s, v);
    ColorProxy proxy = (ColorProxy) ((RubyClass) klass).allocate();
    proxy.setColor(color);
    return proxy;
  }
}
